#include <device/mem.h>

#include <assert.h>

static int mem_read(st_device *dev, riscv_word_t addr, uint8_t *data, int width){
    if((dev->attr & RISCV_MEM_ATTR_READABLE) == 0){
        fprintf(stderr, "read memory failed.\n");
        return -1;
    }
    //
    mem_t *mem = (mem_t *)dev;
    riscv_word_t offset = addr - dev->base;
    //
    if(width == 4){
        *(uint32_t *)data = *(uint32_t *)(mem->mem + offset);
    }else if(width == 2){
        *(uint16_t *)data = *(uint16_t *)(mem->mem + offset);
    }else if(width == 1){
        *(uint8_t *)data = *(uint8_t *)(mem->mem + offset);
    }else{
        memcpy(data, mem->mem + offset, width);
    }
    //
    return 0;
}

static int mem_write(st_device *dev, riscv_word_t addr, uint8_t *data, int width){
    if((dev->attr & RISCV_MEM_ATTR_WRITABLE) == 0){
        fprintf(stderr, "read write failed.\n");
        return -1;
    }
    //
    mem_t *mem = (mem_t *)dev;
    riscv_word_t offset = addr - dev->base;
    //
    if(width == 4){
        *(uint32_t *)(mem->mem + offset) = *(uint32_t *)data;
    }else if(width == 2){
        *(uint16_t *)(mem->mem + offset) = *(uint16_t *)data;
    }else if(width == 1){
        *(uint8_t *)(mem->mem + offset) = *(uint8_t *)data;
    }else{
        memcpy(mem->mem + offset, data, width);
    }
    //
    return 0;
}

mem_t *mem_create(const char *name, riscv_word_t base, riscv_word_t size, riscv_word_t attr)
{
    mem_t * mem = (mem_t *)calloc(1,sizeof(mem_t));
    assert(mem!=NULL);
    mem->mem = (uint8_t *)malloc(size);
    assert(mem->mem!=NULL);
    device_init(&mem->device,name,attr,base,size);
    mem->device.read = mem_read;
    mem->device.write = mem_write;
    return mem;
}
